<template>
	<view class="container">
		<!-- 聊天内容区域 -->
		<scroll-view class="dialog" :scroll-y="true" :scroll-into-view="scrollToView" :scroll-with-animation="true"
			:style="{ paddingBottom: keyboardHeight + 'px' }">
			<view v-for="(chat, index) in chatList" :key="index" class="chat-card">
				<view :style="messageStyle(chat)" class="message-content">
					<block v-for="(o, i) in chat.message" :key="i">
						<text :selectable="true" v-if="o.type === 'text'" class="text-message">{{ o.data.text }}</text>
						<image v-if="o.type === 'image'" :src="'data:image/png;base64,' + o.data.file.substring(9)"
							mode="widthFix" class="image-message" @click="previewImage(o.data.file.substring(9))" />
					</block>
				</view>
			</view>
			<view id="bottom" :style="{ marginBottom: keyboardHeight + 'px' }"></view>
		</scroll-view>

		<!-- 输入区域 -->
		<view class="input-area" :style="{ bottom: keyboardHeight + 'px' }">
			<uni-easyinput type="textarea" class="input-field" v-model="form.message" placeholder="输入消息" maxlength="-1"
				:adjust-position="false" @confirm="submit" />
			<button class="send-btn" @click="submit">发送</button>
		</view>
	</view>
</template>

<script setup>
	import {
		ref,
		nextTick,
		onMounted,
		getCurrentInstance
	} from 'vue'
	import {
		onLoad,
		onUnload,
		onHide,
		onShow
	} from '@dcloudio/uni-app'
	import {
		saveImage, delImage
	} from "@/utils/image"
	import config from "@/config.js"

	const {
		proxy
	} = getCurrentInstance()

	const chatList = ref([])
	const form = ref({
		message: ''
	})
	const scrollToView = ref('')
	const socketTask = ref()

	// 心跳相关参数
	const HEARTBEAT_INTERVAL = 10000; // 10秒发送一次心跳
	const HEARTBEAT_TIMEOUT = 20000; // 20秒未响应视为断开
	let heartbeatTimer = null;
	let lastActivityTime = Date.now();
	let reconnectAttempts = 0;

	// 新增键盘高度监听
	const keyboardHeight = ref(0)
	onMounted(() => {
		uni.onKeyboardHeightChange(res => {
			keyboardHeight.value = res.height
		})
	})

	// 修改后的scrollToView逻辑
	const scrollToBottom = () => {
		nextTick(() => {
			scrollToView.value = 'bottom'
			setTimeout(() => {
				scrollToView.value = ''
			}, 50)
		})
	}

	// 开始发送心跳
	const startHeartbeat = () => {
		heartbeatTimer = setInterval(() => {
			if (Date.now() - lastActivityTime > HEARTBEAT_TIMEOUT) {
				console.log('心跳超时，尝试重连...');
				reconnect();
				return;
			}
			// 发送心跳消息
			const heartbeatData = {
				type: 'heartbeat',
				timestamp: Date.now()
			};
			socketTask.value.send({
				data: JSON.stringify(heartbeatData)
			});
			// console.log('发送心跳消息:', heartbeatData);
		}, HEARTBEAT_INTERVAL);
	};

	// 尝试重新建立连接
	const reconnect = () => {
		reconnectAttempts++;
		if (reconnectAttempts > 3) {
			console.error('重连尝试超过3次，停止重连');
			return;
		}
		console.log(`第 ${reconnectAttempts} 次重连中...`);
		setTimeout(createSocket, Math.min(reconnectAttempts * 1000, 5000));
	};

	// 在 createSocket 前移除旧监听器
	const removeSocketListeners = () => {
		if (!socketTask.value) return
		clearInterval(heartbeatTimer);
		socketTask.value.close()
		socketTask.value = undefined
	}

	// WebSocket相关
	const createSocket = async () => {
		removeSocketListeners(); // 清理旧监听器

		const domain = config.wsUrl
		socketTask.value = uni.connectSocket({
			url: `${domain}/chat/ws`,
			success: () => {
				console.log('连接尝试成功');
				// 全局监听WebSocket事件（小程序端）
				socketTask.value.onOpen(() => {
					console.log('WebSocket连接成功');
					const token = uni.getStorageSync('token') || '';
					if (typeof token !== 'string' || token.trim().length === 0) return
					socketTask.value.send({
						data: JSON.stringify({
							type: 'auth',
							token: token
						}),
						success() {
							reconnectAttempts = 0; // 重置重连计数器
							lastActivityTime = Date.now();
							startHeartbeat();
						}
					});
				});
				// 修改WebSocket消息接收处理
				socketTask.value.onMessage((res) => {
					lastActivityTime = Date.now()
					const data = JSON.parse(res.data)
					if (Array.isArray(data)) {
						data.forEach(item => {
							chatList.value.push({
								action: item.action,
								echo: item.echo,
								message: item.params.message
							})
						})
						scrollToBottom() // 接收消息后滚动到底部
					}
				})
				// 错误处理
				socketTask.value.onError((err) => {
					console.error('WebSocket错误:', err);
				});
				// 关闭后处理
				socketTask.value.onClose(() => {
					console.log('WebSocket连接关闭');
				});
			},
			fail: (err) => {
				console.error('连接失败:', err);
			}
		})
	}

	// 提交消息
	const submit = () => {
		if (!socketTask.value) {
			console.warn('WebSocket 未连接，消息发送失败');
			uni.showToast({
				icon: 'none',
				title: '网络不佳，发送失败'
			})
			return;
		}
		if (!form.value.message.trim()) return
		const token = uni.getStorageSync('token') || '';
		socketTask.value.send({
			data: JSON.stringify({
				type: 'send_msg',
				token: token,
				message: form.value.message
			}),
			success: function() {
				form.value.message = ''
				scrollToBottom() // 发送消息后滚动到底部
			}
		});

	}

	// 消息样式
	const messageStyle = (chat) => {
		return chat.action === 'my_msg' ? {
			backgroundColor: '#E3F2FD',
			color: '#1A5F8A',
		} : {
			backgroundColor: '#FFFFFF',
			color: '#333333',
		}
	}

	// 图片预览
	const previewImage = (base64) => {
		saveImage(base64).then(res => {
			// 预览图片
			uni.previewImage({
				urls: [res],
				complete() {
					const strs = res.split('/')
					const filename = strs[strs.length -1]
					setTimeout(function() {
						delImage(filename)
					},5000)
				}
			});
		}).catch(error => {
			console.error(error);
		})
	}

	onHide(() => {
		removeSocketListeners();
	})

	onShow(() => {
		// 初始化
		createSocket()
	})
</script>

<style lang="scss" scoped>
	page {
		background-color: #fff;
	}

	.container {
		padding: 20rpx;
		height: 100vh;
		display: flex;
		flex-direction: column;
	}

	.dialog {
		height: 80vh;
		border: 1px solid #eee;
		border-radius: 20rpx;
		padding: 20rpx;
		margin-bottom: 20rpx;
		padding-bottom: 0;
		/* 由动态计算替代 */

		.chat-card {
			margin-bottom: 30rpx;

			.message-content {
				padding: 20rpx;
				border-radius: 10rpx;
				max-width: 600rpx;

				.text-message {
					word-break: break-all;
				}

				.image-message {
					// max-width: 400rpx;
					border-radius: 10rpx;
				}
			}
		}
	}

	.input-area {
		display: flex;
		align-items: center;
		padding: 20rpx;
		border: 1px solid #eee;
		border-top-left-radius: 20px;
		border-top-right-radius: 20px;
		position: fixed;
		left: 0;
		right: 0;
		bottom: 0;
		background: white;
		z-index: 999;
		box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);

		.input-field {
			flex: 1;
			// padding: 20rpx;
			border-radius: 40rpx;
			margin-right: 40rpx;
			background-color: #f5f5f5;
		}

		.send-btn {
			padding: 40rpx 40rpx;
			background-color: #007AFF;
			color: white;
			border-radius: 20rpx;
		}
	}
</style>